package com.powernode.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.powernode.constant.MenuConstant;
import com.powernode.domain.SysMenu;
import com.powernode.mapper.SysMenuMapper;
import com.powernode.service.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 内容:
 * 作者: cy
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService {

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 查询他对应的菜单 缓存 加载菜单
     * 1.查缓存
     * 2.查数据库
     * 3.存入缓存
     * 4.转成树菜单
     *
     * @param userId
     * @return
     */
    @Override
    public List<SysMenu> loadSysUserMenu(Long userId) {
        String menuStr = redisTemplate.opsForValue().get(MenuConstant.MENU_PREFIX + userId);
        List<SysMenu> sysMenus = null;
        if (StringUtils.hasText(menuStr)) {
            // 转成list集合  直接在redis存树结构 还是存普通的list结构 在代码里面转换？？
            sysMenus = JSON.parseArray(menuStr, SysMenu.class);
        } else {
            // 查询数据库
            sysMenus = sysMenuMapper.selectMenusByUserId(userId);
            // 再存起来
            if (!CollectionUtils.isEmpty(sysMenus)) {
                // 最好给一个过期时间？  如果不给过期时间 可能会导致redis内存溢出 触发淘汰策略
                redisTemplate.opsForValue().set(MenuConstant.MENU_PREFIX + userId, JSON.toJSONString(sysMenus), Duration.ofDays(7));
            }
        }
        // 父id为0是根节点
        return translateTree(sysMenus, 0L);
    }

    /**
     * 转树结构
     *
     * @param sysMenus
     * @param pid
     * @return
     */
    private List<SysMenu> translateTree(List<SysMenu> sysMenus, long pid) {
        // 如果你知道层级高度 你可以使用多重循环 来转  如果深度超过3级  不建议使用循环
        // 如果你不知道深度 需要使用递归来实现

        // 1.先拿到父id等于0的  根节点 集合
//        List<SysMenu> root = sysMenus.stream()
//                .filter(sysMenu -> sysMenu.getParentId().equals(pid))
//                .collect(Collectors.toList());
//        // 循环根节点
//        root.forEach(r -> {
//            // 过滤出 谁的父id 等于根节点的id 的集合
//            List<SysMenu> childrens = sysMenus.stream()
//                    .filter(sysMenu -> sysMenu.getParentId().equals(r.getMenuId()))
//                    .collect(Collectors.toList());
//            r.setList(childrens);
//        });

        // 递归实现
        List<SysMenu> root = sysMenus.stream()
                .filter(sysMenu -> sysMenu.getParentId().equals(pid))
                .collect(Collectors.toList());
        // 第二步 设置下一级
        root.forEach(r -> r.setList(translateTree(sysMenus, r.getMenuId())));
        return root;
    }
}
